package edu.tamu.cse.teamproject1.Database.Persistence;


import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.*;


import edu.tamu.cse.teamproject1.Database.ColumnDefinition;
import edu.tamu.cse.teamproject1.Database.Database;
import edu.tamu.cse.teamproject1.Database.EnumColumnType;
import edu.tamu.cse.teamproject1.Database.Table;
import edu.tamu.cse.teamproject1.Database.Tuple;
import edu.tamu.cse.teamproject1.Database.TupleDateElement;
import edu.tamu.cse.teamproject1.Database.TupleFloatElement;
import edu.tamu.cse.teamproject1.Database.TupleIntegerElement;
import edu.tamu.cse.teamproject1.Database.TupleVarCharElement;
import edu.tamu.cse.teamproject1.Database.Exceptions.ItemNotFoundException;
import edu.tamu.cse.teamproject1.Database.Interfaces.*;

/**
 * The XMLParser is used to parse XML files specifically designed to 
 * construct the structure of the databases that will inevitably be
 * inside of our database and to fill in those newly constructed
 * tables with values.
 * 
 * @author Ryan McAuley
 * @since Release 0.1.0
 *
 */
public class XMLParser implements IXMLParser{
	DatabaseAPI generatedDatabase;
	ArrayList<IDatabaseTable> generatedTables;
	
	/**
	 * Constructor for XML Parser
	 */
	public XMLParser(){
		generatedDatabase = new Database();
		generatedTables = new ArrayList<IDatabaseTable>();
	}
	
	/**
	 * Parses an XML file that specifically was designed to generate the structure
	 * of a table. This function will generate a table at a time and add it to the
	 * the list of tables. The file name must be specified.
	 * @param filename
	 * 
	 */
	public void createTableStructure(String filename) throws IOException{
		
		/*A list of columns that will be used to generate a table*/
		ArrayList<IColumnDefinition> tableColumns;
		
		GlobalDataStore debugStructure = new GlobalDataStore(); //Used for Testing
		Scanner fileScanner = new Scanner(new BufferedReader(new FileReader(filename)));
		String databaseName;
		String tableName;
		
		debugStructure.deactivateDebugMode();
		
		/*Set the Database's Name*/
		fileScanner.useDelimiter("\">");
		fileScanner.findInLine("database name =\"");
		databaseName = fileScanner.next();
		
		generatedDatabase.setDatabaseName(databaseName);
		
		if(debugStructure.getDebugStatus() == 1){
			System.out.println("The database's name is: " + databaseName);
		}
		
		/**
		 * Loop through the entire column structure XML document, adding
		 * attributes to the column list, and ultimately adding it to a table
		 * that will be added to the ArrayList of Tables. Iteration ends after
		 * seeing the </table> tag.
		 */
		while(fileScanner.hasNextLine()){
			
			tableColumns = new ArrayList<IColumnDefinition>();
			
			fileScanner.nextLine();
			fileScanner.useDelimiter("\\s");
			tableName = fileScanner.next();
			
			/*Gather Information and Generate Table Constructs*/
			if(tableName.equals("<table")){
			
				IDatabaseTable tableAddition;
				fileScanner.useDelimiter("\">");
				fileScanner.findInLine("name=\"");
				tableName = fileScanner.next();
		
				if(debugStructure.getDebugStatus() == 1){
					System.out.println("The table's name is: " + tableName);
				}
			
				/**
				 * Generate the specific column, then add it to the list
				 * of columns.
				 */
				int numOfLoops = 0;
				while(fileScanner.hasNextLine()){
					
					IColumnDefinition addedColumn;
					String tableEnd;
					String columnName;
					String columnType;
					EnumColumnType columnEnumType;
					int columnMaxLength;
					int columnNullValue;
					boolean columnNull;
					int columnKeyValue;
					boolean columnKey;
				
					//Check to see if it is the end of the table
					fileScanner.useDelimiter("\\s");
					fileScanner.nextLine();
					tableEnd = fileScanner.next();
					if(tableEnd.equals("</table>")){
						break;
					}
					
					numOfLoops++;
					
					//Find Column Name
					fileScanner.useDelimiter("\" type");
					fileScanner.findInLine("=\"");
					columnName = fileScanner.next();
				
					//Find Column Type
					fileScanner.useDelimiter("\" maxlength");
					fileScanner.findInLine("=\"");
					columnType = fileScanner.next();
					
					columnEnumType = convertStringToEnum(columnType);
				
					//Find Column maxLength
					fileScanner.useDelimiter("\" null");
					fileScanner.findInLine("=\"");
					columnMaxLength = Integer.parseInt(fileScanner.next());
				
					//Find Column null
					fileScanner.useDelimiter("\" primarykey");
					fileScanner.findInLine("=\"");
					columnNullValue = Integer.parseInt(fileScanner.next());
					if(columnNullValue == 1){
						columnNull = true;
					}
					else{
						columnNull = false;
					}
					
					//Find Column Key Boolean
					fileScanner.useDelimiter("\"></column>");
					fileScanner.findInLine("=\"");
					columnKeyValue = Integer.parseInt(fileScanner.next());
					if(columnKeyValue == 1){
						columnKey = true;
					}
					else{
						columnKey = false;
					}
				
					//Set the column with attributes 
				
					if(debugStructure.getDebugStatus() == 1){
						System.out.println("The column's name is: " + columnName);
						System.out.println("The column's type is: " + columnType);
						System.out.println("The column's maxlength is: " + columnMaxLength);
						System.out.println("The column's null is: " + columnNull);
						System.out.println("The column's key is: " + columnKey);
						System.out.println("");
					}
				
					
					/*Flll the column with the determined parameters and add it to the list*/
					addedColumn = new ColumnDefinition(columnEnumType, columnName, columnKey);
					addedColumn.setNullable(columnNull);
					addedColumn.setColumnSize(columnMaxLength);
					tableColumns.add(addedColumn);
				
				}
				
				//System.out.println("numOfColumns: " + numOfLoops);
				
				if(debugStructure.getDebugStatus() == 1){
					System.out.print("\n");
				}
				
				tableAddition = new Table(tableName, tableColumns);

				generatedTables.add(tableAddition);
			}
		}

		fileScanner.close();
	}
	
	
	/**
	 * Parses an XML File that is specifically designed to generate tuples for
	 * the structured table. Adds the tuple to the table by the table name. The
	 * filename must be specified.
	 * @param filename
	 */
	 public void fillTable(String filename) throws IOException{ 
		GlobalDataStore debugFill = new GlobalDataStore(); //Used for Testing
		Scanner fileScanner = new Scanner(new BufferedReader(new FileReader(filename)));
		String tableName;
		String tupleParameter;
		String tupleValue;
		String test;
		
		debugFill.deactivateDebugMode();
		
		if(fileScanner.next().equals("<databaseValues>")){
			fileScanner.nextLine();
		}
		
		/**
		 * Adds all tuples to a table. Next iteration is the end of a table.
		 */
		/*Find the name of the table whose data is being generated*/
		while(fileScanner.hasNextLine()){
			fileScanner.useDelimiter(">");
			fileScanner.findInLine("<");
			tableName = fileScanner.next();
		
			fileScanner.useDelimiter("\\s");
			
			/**
			 * Generates a tuple at a time and adds it to the tuple list. Next iteration
			 * is the end of a tuple.
			 */
			/*Gather all Tuples for this table*/
			while(fileScanner.hasNextLine()){
				fileScanner.nextLine(); //Skip <tuple> tag
				
				if(fileScanner.hasNext()){
					test = fileScanner.next();
				}
				
				else
					break;
				
				if(!(test.equals("	</"+tableName))){
					
					if(debugFill.getDebugStatus() == 1){
						System.out.println("\nGenerating Data For: " +tableName);
					}
					
					ArrayList <String> tupleValues = new ArrayList<String>();
					ArrayList <String> tupleParameters = new ArrayList<String>();
					
					/**
					 * Grabs the value from a tuple. Iteration ends on seeing a </whatever> 
					 */
					while(fileScanner.hasNextLine()){
						fileScanner.nextLine();
					
						/*Find the Parameter of the Tuple*/
						fileScanner.useDelimiter(">");
						fileScanner.findInLine("<");
						tupleParameter = fileScanner.next();
						
						/*Add the Parameter to the String Array*/
						tupleParameters.add(tupleParameter);
					
						/*Exit at End of Tuple*/
						if(tupleParameter.equals("/tuple")){
							tupleParameters.remove(tupleParameters.size()-1);
							break;
						}
					
						/*Find the Value for the Parameter*/
						fileScanner.useDelimiter("</");
						fileScanner.findInLine(">");
						tupleValue = fileScanner.next();
						
						/*Add the Value to the String Array*/
						tupleValues.add(tupleValue);
						
						if(debugFill.getDebugStatus() == 1){
							System.out.println("Tuple parameter: " + tupleParameter);
							System.out.println("The tuple value: " + tupleValue);
						}
					
						fileScanner.useDelimiter("\\s");
					}
					
					if(debugFill.getDebugStatus() == 1){
						System.out.println("The current size of paramaters is: " +tupleParameters.size());
						System.out.println("The current size of the values is: " +tupleValues.size());
					}
					
					/*Generate the Tuples for the given Table*/
					parseTuple(tupleValues, tupleParameters, tableName);
				
					
				}
				else
					break;
			}
			
			if(fileScanner.hasNextLine()){
				fileScanner.nextLine();
			}
		
		}
		fileScanner.close();
	}
	 
	 
	 
	/**
	 * Returns the fully parsed database
	 * @return generatedDatabase
	 */
	public DatabaseAPI getGeneratedDatabase(){
		generatedDatabase.addListOfTables(generatedTables);
		return generatedDatabase;
	}

	/**
	 * Helper function used to determine a column's Enum type. Used to convert the
	 * strings extracted from the table structure XML file and converts them over to
	 * the proper Enum type.
	 * @param name
	 * @return determinedType
	 */
	public EnumColumnType convertStringToEnum(String name){
		EnumColumnType determinedType;
		
		/*Set the determined type based off of the name paramater*/
		if(name.equals("varchar")){
			determinedType = EnumColumnType.varchar;
		}
		else if(name.equals("character")){
			determinedType = EnumColumnType.character;
		}
		else if(name.equals("integer") || name.equals("int")){
			determinedType = EnumColumnType.integer;
		}
		else if (name.equals("floating") || name.equals("float")){
			determinedType = EnumColumnType.floating;
		}
		else if (name.equals("date")){
			determinedType = EnumColumnType.date;
		}
		else{
			throw new IllegalArgumentException("Unknown Enumeration Type: " + name);
		}
		return determinedType;
	}
	
	/**
	 * Generic way to parse a Tuple of any type, not just the types defined by the API
	 * @param tupleData
	 * @param tupleParameters
	 */
	void parseTuple(ArrayList<String> tupleData, ArrayList<String> tupleParameters, String tableName){
		List <ITupleElement> tupleElements = new ArrayList<ITupleElement>();
		IDatabaseTable determinedTable = null;
		ITuple generatedTuple;
		IColumnDefinition matchingColumn = null;
		String currentTupleParameter;
		EnumColumnType tupleEnumType = null;
		int tableIndex = -1;
		
		/*Get the table where the tuples are going to be stored*/
		for(int i = 0; i < generatedTables.size(); i++){
			if(tableName.equals(generatedTables.get(i).getName())){
				determinedTable = generatedTables.get(i);
				tableIndex = i;
				break;
			}
		}
		
		
		if(tupleData.size() == tupleParameters.size()){
			/*Loop through each TupleElements columnName and value*/
			for(int i = 0; i < tupleData.size(); i++){
				currentTupleParameter = tupleParameters.get(i);
				try {
					tupleEnumType = getTupleType(currentTupleParameter, determinedTable);
				} catch (ItemNotFoundException e) {
					e.printStackTrace();
				}
				
				/*Get the column that matches the tupleElement being added*/
				boolean foundColumn = false;
				for(IColumnDefinition c: determinedTable.getColumnLists()){
					if(c.getColumnName().equals(currentTupleParameter)){
						foundColumn = true;
						matchingColumn = c;
					}
				}
				if(foundColumn == false) 
					throw new InputMismatchException("could not find column: " + currentTupleParameter);
				
				/*Add the tupleElement to the tuple*/
				 tupleElements.add(createTupleElement(tupleEnumType, tupleData.get(i), matchingColumn));
			}
			/*Add the TupleElements into a new tuple*/
			generatedTuple = new Tuple(tupleElements);
		}
		
		else
			throw new IllegalArgumentException("Tuple Data and parameters do not match!");
		
		/*Add the tuple into the table*/
		this.generatedTables.get(tableIndex).addTuple(generatedTuple);
	}
	
	/**
	 * Used to determine the type of tuple for a generic tuple parse
	 * @param tupleParameter
	 * @param determinedTable
	 * @return column.getColumnType();
	 * @throws ItemNotFoundException
	 */
	EnumColumnType getTupleType(String tupleParameter,
								IDatabaseTable determinedTable) throws ItemNotFoundException{
		String columnName;
		boolean foundMatch = false;
		/*Find the column that matches the tupleElement*/
		for(IColumnDefinition c: determinedTable.getColumnLists()){
			columnName = c.getColumnName();
			
			//System.out.println(columnName + " ?= " + tupleParameter);
			
			/*If column found return its type*/
			if(columnName.equals(tupleParameter)){
				foundMatch = true;
				return c.getColumnType();
			}
		}
		if(!foundMatch){
			throw new ItemNotFoundException("Cannot find column of the name: " + tupleParameter);
		}
		return null;
	}
	
	/**
	 * Used to create a generic tuple element from any kind of database
	 * @param determinedType
	 * @param value
	 * @param columnName
	 * @return generatedTupleElement
	 */
	ITupleElement createTupleElement(EnumColumnType determinedType, String value, 
												IColumnDefinition matchingColumn){
		ITupleElement generatedTupleElement = null;
		DateFormat myDateFormat = new SimpleDateFormat("mm/dd/yyyy");
		
		/*Find which type the new tupleElement is and add the value to the new tupleElement*/
		if(determinedType == EnumColumnType.integer){
			Integer convertedInteger = Integer.parseInt(value);
			generatedTupleElement = new TupleIntegerElement(convertedInteger);
		}
		else if(determinedType == EnumColumnType.varchar){
			generatedTupleElement = new TupleVarCharElement(value);
		}
		else if(determinedType == EnumColumnType.date){
			try {
				Date convertedDate;
			    convertedDate  = myDateFormat.parse(value);
			    generatedTupleElement = new TupleDateElement(convertedDate);
			    
			} catch (ParseException e) {
			     System.out.println("Invalid Date Parser Exception ");
			     e.printStackTrace();
			}
		}
		else if(determinedType == EnumColumnType.floating){
			Float convertedFloat = Float.valueOf(value).floatValue();
			generatedTupleElement = new TupleFloatElement(convertedFloat);
		}
		else
			throw new IllegalArgumentException("Tuple cannot be matched to column!");
		
		
		/*Set the tupleElements ColumnName, key, and isNullable*/
		generatedTupleElement.setColumnName(matchingColumn.getColumnName());
		generatedTupleElement.setAsKey(matchingColumn.isKey());
		generatedTupleElement.setNullable(matchingColumn.isNullable());
		
		return generatedTupleElement;
	}

	/**********************************************************
	 * CODE Tests - Hard Coded Functions Matching API Specs
	 **********************************************************/
	
	/**
	 * Helper function used to generate a tuple for the FlightInfo table. Converts all of the
	 * strings parsed out of the function in the designated format and adds them into a
	 * tuple.
	 * @param flightInfoData
	 * @return generatedTuple
	 */
	Tuple parseFlightInfoTuple(ArrayList <String> flightInfoData){
		Tuple generatedTuple = new Tuple();
		DateFormat myDateFormat = new SimpleDateFormat("mm/dd/yyyy");
		int size = flightInfoData.size();
		
		int FlightNumber;
		String PlaneID;
		int TerminalNumber;
		int PassengerCapacity;
		int NumberOfPassengers;
		Date DepartureDate;
		String DepartureTime;
		String ArrivalTime;
		String Destination;
		int DestinationTimeInMin;
		
		
		/*Set the individual Tuple values to their designated types and add to returned Tuple*/
		for(int i = 0; i< size; i++){
			if(i == 0){
				FlightNumber= Integer.parseInt(flightInfoData.get(i));
				ITupleElement flightNumberElement = new TupleIntegerElement(FlightNumber);
				flightNumberElement.setColumnName("FlightNumber");
				flightNumberElement.setAsKey(true); //Key
				generatedTuple.addTupleElement(flightNumberElement);
			}
			else if(i == 1){
				PlaneID= flightInfoData.get(i);
				ITupleElement planeIDElement = new TupleVarCharElement(PlaneID);
				planeIDElement.setColumnName("PlaneID");
				generatedTuple.addTupleElement(planeIDElement);
			}
			else if(i == 2){
				TerminalNumber = Integer.parseInt(flightInfoData.get(i));
				ITupleElement terminalNumberElement = new TupleIntegerElement(TerminalNumber);
				terminalNumberElement.setColumnName("TerminalNumber");
				generatedTuple.addTupleElement(terminalNumberElement);
			}
			else if(i == 3){
				PassengerCapacity = Integer.parseInt(flightInfoData.get(i));
				ITupleElement capacityElement = new TupleIntegerElement(PassengerCapacity);
				capacityElement.setColumnName("PassengerCapacity");
				generatedTuple.addTupleElement(capacityElement);
			}
			else if(i == 4){
				NumberOfPassengers = Integer.parseInt(flightInfoData.get(i));
				ITupleElement numPassengersElement = new TupleIntegerElement(NumberOfPassengers);
				numPassengersElement.setColumnName("NumberOfPassengers");
				generatedTuple.addTupleElement(numPassengersElement);
			}
			else if(i == 5){
				try {
				    DepartureDate  = myDateFormat.parse(flightInfoData.get(i));
				    ITupleElement dateElement = new TupleDateElement(DepartureDate);
				    dateElement.setColumnName("DepartureDate");
					generatedTuple.addTupleElement(dateElement);
				} catch (ParseException e) {
				     System.out.println("Invalid Date Parser Exception ");
				     e.printStackTrace();
				}
			}
			else if(i == 6){
				DepartureTime = flightInfoData.get(i);
				ITupleElement departureElement = new TupleVarCharElement(DepartureTime);
				departureElement.setColumnName("DepartureTime");
				generatedTuple.addTupleElement(departureElement);
			}
			else if(i == 7){
				ArrivalTime = flightInfoData.get(i);
				ITupleElement arrivalElement = new TupleVarCharElement(ArrivalTime);
				arrivalElement.setColumnName("ArrivalTime");
				generatedTuple.addTupleElement(arrivalElement);
			}
			else if(i == 8){
				Destination = flightInfoData.get(i);
				ITupleElement destinationElement = new TupleVarCharElement(Destination);
				destinationElement.setColumnName("Destination");
				generatedTuple.addTupleElement(destinationElement);
			}
			else if(i == 9){
				DestinationTimeInMin = Integer.parseInt(flightInfoData.get(i));
				ITupleElement timeInMinElement = new TupleIntegerElement(DestinationTimeInMin);
				timeInMinElement.setColumnName("DestinationTimeInMin");
				generatedTuple.addTupleElement(timeInMinElement);
			}
			else{
				throw new IllegalArgumentException("FlightInfo Tuple Error");
			}
		}
		return generatedTuple;
	}
	
	/**
	 * Helper function used to generate a tuple for the PassengerInfo table. Converts all of the
	 * strings parsed out of the function in the designated format and adds them into a
	 * tuple.
	 * @param  flightInfoData
	 * @return generatedTuple
	 */
	Tuple parsePassengerInfoTuple(ArrayList <String> passengerInfoData){
		Tuple generatedTuple = new Tuple();
		DateFormat myDateFormat = new SimpleDateFormat("mm/dd/yyyy");
		int size = passengerInfoData.size();
		
		int PassengerID;
		String LastName;
		String FirstName;
		String Address;
		int FrequentFlierMiles;
		String FirstClass;
		Date DateOfBirth;
		
		/*Set the individual Tuple values to their designated types and add to returned Tuple*/
		for(int i = 0; i< size; i++){
			if(i == 0){
				PassengerID= Integer.parseInt(passengerInfoData.get(i));
				ITupleElement flightIDElement = new TupleIntegerElement(PassengerID);
				flightIDElement.setColumnName("PassengerID");
				flightIDElement.setAsKey(true); //Key
				generatedTuple.addTupleElement(flightIDElement);
			}
			else if(i == 1){
				LastName= passengerInfoData.get(i);
				ITupleElement lastNameElement = new TupleVarCharElement(LastName);
				lastNameElement.setColumnName("LastName");
				generatedTuple.addTupleElement(lastNameElement);
			}
			else if(i == 2){
				FirstName = passengerInfoData.get(i);
				ITupleElement firstNameElement = new TupleVarCharElement(FirstName);
				firstNameElement.setColumnName("FirstName");
				generatedTuple.addTupleElement(firstNameElement);
			}
			else if(i == 3){
				Address = passengerInfoData.get(i);
				ITupleElement addressElement = new TupleVarCharElement(Address);
				addressElement.setColumnName("Address");
				generatedTuple.addTupleElement(addressElement);
			}
			else if(i == 4){
				FrequentFlierMiles = Integer.parseInt(passengerInfoData.get(i));
				ITupleElement ffmElement = new TupleIntegerElement(FrequentFlierMiles);
				ffmElement.setColumnName("FrequentFlierMiles");
				generatedTuple.addTupleElement(ffmElement);
			}
			else if(i == 5){
				FirstClass = passengerInfoData.get(i);
				ITupleElement firstclassElement = new TupleVarCharElement(FirstClass);
				firstclassElement.setColumnName("FirstClass");
				generatedTuple.addTupleElement(firstclassElement);
			}
			else if(i == 6){
				try {
				    DateOfBirth  = myDateFormat.parse(passengerInfoData.get(i));
				    ITupleElement dobElement = new TupleDateElement(DateOfBirth);
				    dobElement.setColumnName("DateOfBirth");
					generatedTuple.addTupleElement(dobElement);
				} catch (ParseException e) {
				     System.out.println("Invalid Date Parser Exception ");
				     e.printStackTrace();
				}
			}
			else{
				throw new IllegalArgumentException("PassengerInfo Tuple Error");
			}
		}
		return generatedTuple;
	}
	
	/**
	 * Helper function used to generate a tuple for the TicketInfo table. Converts all of the
	 * strings parsed out of the function in the designated format and adds them into a
	 * tuple.
	 * @param flightInfoData
	 * @return generatedTuple
	 */
	Tuple parseTicketInfoTuple(ArrayList <String> ticketInfoData){
		Tuple generatedTuple = new Tuple();
		DateFormat myDateFormat = new SimpleDateFormat("mm/dd/yyyy");
		int size = ticketInfoData.size();
		
		int TicketID;
		int FlightNumber;
		Date TicketDate;
		int PassengerID;
		float Cost;
		
		/*Set the individual Tuple values to their designated types and add to returned Tuple*/
		for(int i = 0; i< size; i++){
			if(i == 0){
				TicketID= Integer.parseInt(ticketInfoData.get(i));
				ITupleElement ticketIDElement = new TupleIntegerElement(TicketID);
				ticketIDElement.setColumnName("TicketID");
				ticketIDElement.setAsKey(true); //Key
				generatedTuple.addTupleElement(ticketIDElement);
			}
			else if(i == 1){
				FlightNumber = Integer.parseInt(ticketInfoData.get(i));
				ITupleElement flightNumberElement = new TupleIntegerElement(FlightNumber);
				flightNumberElement.setColumnName("FlightNumber");
				generatedTuple.addTupleElement(flightNumberElement);
			}
			else if(i == 2){
				try {
				    TicketDate  = myDateFormat.parse(ticketInfoData.get(i));
				    ITupleElement ticketDateElement = new TupleDateElement(TicketDate);
				    ticketDateElement.setColumnName("Date");
					generatedTuple.addTupleElement(ticketDateElement);
				} catch (ParseException e) {
				     System.out.println("Invalid Date Parser Exception ");
				     e.printStackTrace();
				}
			}
			else if(i == 3){
				PassengerID = Integer.parseInt(ticketInfoData.get(i));
				ITupleElement passengerIDElement = new TupleIntegerElement(PassengerID);
				passengerIDElement.setColumnName("PassengerID");
				generatedTuple.addTupleElement(passengerIDElement);
			}
			else if(i == 4){
				Cost = Float.valueOf(ticketInfoData.get(i)).floatValue();
				ITupleElement costElement = new TupleFloatElement(Cost);
				costElement.setColumnName("Cost");
				generatedTuple.addTupleElement(costElement);
			}
			else{
				throw new IllegalArgumentException("Tuple Paramaters Flawed");
			}
		}
		return generatedTuple;
	}

}
